/**
 * 导入仓库 svn导入方式
 * @param type 默认normal, retry：重新导入
 * @param projectInfo 默认为null，默认数据，在重新导入时用到
 * @param retryCallback 重新导入成功的回调
 */

import React from 'react';
import PropTypes from 'prop-types';
import { Form, Input, Field, Grid, Balloon, Radio } from '@teamix/ui';
import { ButtonIcon, YunxiaoIcon } from '@alife/devops-ui';
import { ENUM } from 'utils/constants.js';
import exceed from 'utils/apimap';
import AccessSelect from 'components/accessSelect';
import debounce from 'lodash.debounce';
import docs from 'utils/docs';
import { checkProjectName } from 'api/index.js';
import { encrypt } from 'utils/JSEncrypt';
import { navigate, navigateHref } from 'utils/router';
import GroupSelect from 'components/groupSelect';
import AddonBeforeInputSpan from 'components/addonBeforeInput/span';
import intl from '../../../locale';

const FormItem = Form.Item;
const formItemLayout = {
  labelCol: {
    span: 6,
  },

  wrapperCol: {
    span: 14,
  },
};

const { organization } = window.FORCE;
const svnTypes = ['trunk', 'branches', 'tags'];

export default class ImportProjectByUrlModal extends React.Component {
  static propTypes = {
    defaultNamespaceId: PropTypes.string,
    trigger: PropTypes.element,
    closeModal: PropTypes.func,
    isModalOpen: PropTypes.bool,
    type: PropTypes.string,
    projectInfo: PropTypes.object,
    retryCallback: PropTypes.func,
  };

  static defaultProps = {
    defaultNamespaceId: '',
    trigger: null,
    closeModal: () => {},
    type: 'normal', // 默认为normal, retry 重新导入
    projectInfo: {
      import_url: '',
      id: '',
    },

    retryCallback: () => {},
  };

  constructor(props) {
    super(props);
    this.field = new Field(this, {
      onChange: (name, value) => {
        if (name === 'namespace_id') {
          this.field.validate();
        }
        if (name === 'import_url' && value && props.type === 'normal') {
          const arr = value.split('/');
          const end = arr.length > 1 ? arr[arr.length - 1] : '';
          const projectName = end.split('.')[0];
          this.field.setValue('name', projectName);
          this.field.setValue('path', projectName);
          this.field.validate();
        }
        if (name === 'name') {
          this.field.setValue('path', value);
          this.field.validate();
        }
      },
    });

    this.state = {
      groupAccess: '',
      // 组的校验是否需要必选校验
      groupSelectRules: [],
      // 聚焦时调整z-index
      namespaceIdFocus: false,
      import_svn_repo_config: {
        standard_layout: true, // 是否是标准布局
        root_is_trunk: true, // 使用root目录，选中传true，未选中传false
        no_branches: true, // 不导入branches，选中该项传true，未选中传false
        no_tags: true, // 不导入tags，选中该项传true，未选中传false
        trunk_mapping: '', // 自定义trunk导入目录，未填不传该参数
        branch_mapping: '', // 自定义branch导入目录，未填不传该参数
        tag_mapping: '', // 自定义tag导入目录，未填不传该参数
      },
      svnRadioMap: {
        trunk: 'root_is_trunk',
        branches: 'no_branches',
        tags: 'no_tags',
      },

      svnInputMap: {
        trunk: 'trunk_mapping',
        branches: 'branch_mapping',
        tags: 'tag_mapping',
      },
    };

    this.checkPath = debounce(this.checkPath, 500);
    this.checkName = debounce(this.checkName, 500);
  }

  setGroupAccess = (item) => {
    this.setState({
      groupAccess: item.visibility_level,
    });

    this.field.setValue({
      visibility_level: ENUM.visibility_level.PRIVATE,
    });
  };

  checkName(value, callback) {
    let namespace_id = this.field.getValue('namespace_id');
    if (!Number(namespace_id)) {
      namespace_id = organization.namespace_id || '';
    }
    checkProjectName({ name: value, namespace_id })
      .then(() => {
        callback();
      })
      .catch((err) => {
        const errCause = JSON.parse(err.responseText).cause;
        callback(`${errCause}`);
      });
  }

  checkPath(value, callback) {
    let namespace_id = this.field.getValue('namespace_id');
    if (!Number(namespace_id)) {
      namespace_id = organization.namespace_id || '';
    }

    checkProjectName({ path: value, namespace_id })
      .then(() => {
        callback();
      })
      .catch((err) => {
        const errCause = JSON.parse(err.responseText).cause;
        callback(`${errCause}`);
      });
  }

  nameValidator = (rule, value, callback) => {
    if (!value) {
      callback();
      return;
    }
    if (/^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,}$/.test(value)) {
      this.checkName(value, callback);
    } else {
      callback(
        intl.get({
          id: 'code-assets.src.utils.locale.ItCanOnlyContainLetters',
          defaultMessage: "只能包含字母和数字、 '_'、 '.'和'-'，且只能以字母、数字或'_'开头",
        }),
      );
    }
  };

  pathValidator = (rule, value, callback) => {
    if (!value) {
      callback();
      return;
    }
    if (/^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,}$/.test(value)) {
      this.checkPath(value, callback);
    } else {
      callback(
        intl.get({
          id: 'code-assets.src.utils.locale.ItCanOnlyContainLetters',
          defaultMessage: "只能包含字母和数字、 '_'、 '.'和'-'，且只能以字母、数字或'_'开头",
        }),
      );
    }
  };

  gitValidator = (rule, value, callback) => {
    if (!value) {
      callback();
      return;
    }
    if (!/^((https|http|git|svn)?:\/\/)[^\s]+/.test(value)) {
      callback(
        intl.get({
          id: 'code-assets.importProjectModal.svn.TheUrlOfTheCode',
          defaultMessage: '代码库地址请以 http://, https://, 或者 svn://开头',
        }),
      );
    } else {
      callback();
    }
  };

  setVisibilityLevel = (value) => {
    this.field.setValue('visibility_level', value);

    // 全部禁用时需要提醒
    if (value === '' || value === undefined) {
      this.field.setError(
        'visibility_level',
        intl.get({
          id: 'code-assets.src.utils.locale.ThisParameterIsRequired',
          defaultMessage: '该项为必填项',
        }),
      );
    } else {
      this.field.setError('visibility_level', '');
    }
  };

  handleOk = () => {
    const { projectInfo, type: importType } = this.props;
    const { import_svn_repo_config, svnInputMap, svnRadioMap } = this.state;
    const { pathResource } = window.FORCE;
    // 点击确定时，进行校验
    svnTypes.forEach((item) => {
      const isInputDisabled =
        import_svn_repo_config.standard_layout || import_svn_repo_config[svnRadioMap[item]];
      this.setConfigError(import_svn_repo_config[svnInputMap[item]], item, isInputDisabled);
    });
    this.field.validate((errors) => {
      if (!errors) {
        if (this.props.submitting) {
          return;
        }
        this.props.setSubmitting(true);
        const formData = this.field.getValues();
        formData.create_parent_path = true;
        // 重试导入添加参数namespace_id + path
        if (importType === 'retry') {
          formData.namespace_id = pathResource.parentId;
          formData.path = projectInfo.path;
        }
        // 后台需要暂时先写上
        if (!Number(formData.namespace_id)) {
          formData.namespace_id = organization.namespace_id || '';
          formData.create_parent_path = false;
        }
        formData.open_department_id_paths = [];
        if (formData.import_token) {
          formData.import_token_encrypted = 'rsa'; // 使用加密
          formData.import_token = encrypt(formData.import_token, this.props.PUBLIC_KEY);
        } else {
          formData.import_token_encrypted = 'text';
        }

        // 账号编码一下
        if (formData.import_account) {
          formData.import_account = encodeURIComponent(formData.import_account);
        }

        const svnConfig = JSON.parse(JSON.stringify(this.state.import_svn_repo_config));
        if (svnConfig && svnConfig.standard_layout) {
          svnConfig.root_is_trunk = false;
          svnConfig.no_branches = false;
          svnConfig.no_tags = false;
        }

        // SVN 导入需要2个参数
        const curFormData = {
          ...formData,
          import_repo_type: 'svn',
          import_svn_repo_config: this.state.import_svn_repo_config,
        };

        this.formSubmit(curFormData, (type) => {
          this.props.setSubmitting(false);
          if (type !== 'isFail') {
            this.props.onClose();
          }
        });

        // 描述信息和可见性修改后保存
        if (
          importType === 'retry' &&
          (formData.description !== projectInfo.description ||
            formData.visibility_level !== projectInfo.visibility_level)
        ) {
          this.updateProject({
            ...projectInfo,
            description: formData.description,
            visibility_level: formData.visibility_level,
          });
        }
      }
    });
  };

  updateProject = (data) => {
    exceed
      .fetch({
        api: 'projects.settings.edit',
        params: {
          id: this.props.projectInfo.id,
        },

        data,
      })
      .then(() => {})
      .fail((err) => {
        console.error(err);
      });
  };

  onChangeConfig = (value, item) => {
    // this.field.setValue('ref', value);
    this.setConfigError(value, item);
  };

  // ignore 输入框禁用不用校验
  setConfigError = (value, item, ignore = false) => {
    if (value || ignore) {
      this.field.setError(item, '');
    } else {
      this.field.setError(
        item,
        intl.get({
          id: 'code-assets.importProjectModal.svn.TheDirectoryLocationIsRequired',
          defaultMessage: '目录位置为必填项',
        }),
      );
    }
  };

  /**
   * 改变svn的值
   * @param {*} value 值
   * @param {*} item key
   * @param {*} type input/radio
   */
  changeSvnInfo = (value, item, type) => {
    const { import_svn_repo_config, svnRadioMap, svnInputMap } = this.state;
    const key = type === 'radio' ? svnRadioMap[item] : svnInputMap[item];
    const curConfig = {
      ...import_svn_repo_config,
      [key]: value,
    };

    // 清空输入内容
    if (type === 'radio' && value) {
      curConfig[svnInputMap[item]] = '';
      this.setConfigError(value, item, true);
    }
    // 改变输入框时，设置错误信息
    const isInputDisabled = curConfig.standard_layout || curConfig[svnRadioMap[item]];
    this.setConfigError(curConfig[svnInputMap[item]], item, isInputDisabled);
    this.setState({
      import_svn_repo_config: curConfig,
    });
  };

  renderSvnInfo = (item) => {
    const { import_svn_repo_config, svnRadioMap, svnInputMap } = this.state;
    const value = import_svn_repo_config[svnRadioMap[item]];
    const text = import_svn_repo_config[svnInputMap[item]];
    return (
      <div className="svn-item">
        <FormItem
          label={item}
          required
          className={this.field.getState(item) === 'error' ? 'has-error' : ''}
          help={
            this.field.getState(item) === 'error' ? (
              <div>
                <YunxiaoIcon type="delete-fill" />
                <span className="next-form-item-help-text">{this.field.getError(item)}</span>
              </div>
            ) : (
              ''
            )
          }
        >
          <Radio.Group
            value={value}
            itemDirection="ver"
            onChange={(v) => {
              this.changeSvnInfo(v, item, 'radio');
            }}
          >
            <Radio value>
              {item === 'trunk'
                ? intl.get({
                    id: 'code-assets.importProjectModal.svn.UseTheRootDirectory',
                    defaultMessage: '使用 Root 目录',
                  })
                : intl.get({
                    id: 'code-assets.importProjectModal.svn.DoNotImport',
                    defaultMessage: '不导入',
                  })}
            </Radio>
            <Radio value={false}>
              <span>
                <span>
                  {intl.get({
                    id: 'code-assets.importProjectModal.svn.CustomDirectory',
                    defaultMessage: '自定义目录',
                  })}
                </span>
                <Input
                  value={text}
                  style={{ marginLeft: 40 }}
                  disabled={value}
                  placeholder={intl.get({
                    id: 'code-assets.importProjectModal.svn.EnterTheDirectoryLocation',
                    defaultMessage: '请填写目录位置',
                  })}
                  onChange={(v) => {
                    this.changeSvnInfo(v, item, 'input');
                  }}
                />
              </span>
            </Radio>
          </Radio.Group>
        </FormItem>
      </div>
    );
  };

  formSubmit = (formData, cb) => {
    const { type, retryCallback } = this.props;
    exceed
      .fetch({
        api: type === 'normal' ? 'projects.post' : 'projects.single.import',
        params: {
          id: this.props.projectInfo.id,
        },

        data: { ...formData, namespace_id: Number(formData.namespace_id) },
      })
      .then((result) => {
        // 错误页面直接跳转
        const isErrorPage = window.ERROR && window.ERROR.errorCode;
        if (isErrorPage) {
          navigateHref(`/${result.path_with_namespace}`);
        } else if (type === 'retry') {
          retryCallback();
        } else {
          navigate(`/${result.path_with_namespace}`, { state: { forceUpdate: true } });
        }

        cb && cb();
      })
      .fail(() => {
        // 接口报错也要回调，以让按钮取消loading状态但是弹窗不关闭
        cb && cb('isFail');
      });
  };

  handleChangeAccess = (value) => {
    this.field.setValue('visibility_level', value);
  };

  setGroupNeedValidate = (isNeed) => {
    this.setState({
      groupSelectRules: isNeed
        ? [
            {
              required: true,
              message: intl.get({
                id: 'code-assets.src.utils.locale.ThisParameterIsRequired',
                defaultMessage: '该项为必填项',
              }),
            },
          ]
        : [],
    });
  };

  render() {
    const { init } = this.field;
    const { groupSelectRules, namespaceIdFocus, import_svn_repo_config } = this.state;

    const { type, projectInfo } = this.props;
    const {
      import_url,
      name: projectName,
      visibility_level: curProjectVisibilityLevel,
      description,
      web_url,
    } = projectInfo;
    return (
      <React.Fragment>
        <Form {...formItemLayout} field={this.field} labelAlign="top">
          <FormItem
            label={intl.get({
              id: 'code-assets.importProjectModal.svn.SourceCodeLibraryAddress',
              defaultMessage: '源代码库地址',
            })}
            required
          >
            <Input
              autoFocus
              placeholder={intl.get({
                id: 'code-assets.importProjectModal.svn.EnterTheSvnRepositoryAddress',
                defaultMessage: '请输入 SVN 仓库地址，如 svn://host/repo',
              })}
              {...init('import_url', {
                rules: [
                  {
                    required: true,
                    message: intl.get({
                      id: 'code-assets.importProjectModal.svn.ThisParameterIsRequired',
                      defaultMessage: '该项为必填项',
                    }),
                  },

                  {
                    validator: this.gitValidator,
                  },
                ],

                initValue: import_url,
              })}
            />
          </FormItem>
          <Grid.Row gutter={20} className="import-url-account-token">
            <Grid.Col span={12}>
              <FormItem
                label={intl.get({
                  id: 'code-assets.importProjectModal.svn.Account',
                  defaultMessage: '帐号',
                })}
              >
                <Input
                  placeholder={intl.get({
                    id: 'code-assets.importProjectModal.svn.EnterAnAccount',
                    defaultMessage: '请输入帐号',
                  })}
                  {...init('import_account', {
                    // rules: [],
                    initValue: '',
                  })}
                />
              </FormItem>
            </Grid.Col>
            <Grid.Col>
              <FormItem
                label={intl.get({
                  id: 'code-assets.importProjectModal.svn.Password',
                  defaultMessage: '密码',
                })}
              >
                <Input
                  placeholder={intl.get({
                    id: 'code-assets.importProjectModal.svn.EnterAPassword',
                    defaultMessage: '请输入密码',
                  })}
                  htmlType="password"
                  {...init('import_token', {
                    // rules: [],
                    initValue: '',
                  })}
                />
              </FormItem>
            </Grid.Col>
          </Grid.Row>

          <FormItem
            className="import-svn-info"
            label={
              <span>
                <span className="before-icon-text">
                  {intl.get({
                    id: 'code-assets.importProjectModal.svn.ImportMappings',
                    defaultMessage: '导入映射',
                  })}
                </span>
                <Balloon
                  align="t"
                  trigger={
                    <ButtonIcon
                      name="question-line"
                      type="secondary"
                      className="access-token-help"
                    />
                  }
                  type="normal"
                  closable={false}
                >
                  <a href={docs('svn-import')} target="_blank" rel="noreferrer">
                    {intl.get({
                      id: 'code-assets.importProjectModal.svn.HowDoISetThe',
                      defaultMessage: '如何设置导入映射？',
                    })}
                  </a>
                </Balloon>
              </span>
            }
            required
          >
            <Radio.Group
              itemDirection="ver"
              value={import_svn_repo_config.standard_layout}
              onChange={(v) => {
                this.setState({
                  import_svn_repo_config: {
                    ...import_svn_repo_config,
                    standard_layout: v,
                  },
                });
              }}
            >
              <Radio value>
                {intl.get({
                  id: 'code-assets.importProjectModal.svn.StandardLayoutTrunkTagsBranches',
                  defaultMessage: '标准布局（trunk，tags，branches）',
                })}
              </Radio>
              <Radio value={false}>
                {intl.get({
                  id: 'code-assets.importProjectModal.svn.NonStandardLayout',
                  defaultMessage: '非标准布局',
                })}
              </Radio>
            </Radio.Group>
          </FormItem>

          {!import_svn_repo_config.standard_layout && (
            <div className="import-svn-list">
              {svnTypes.map((item) => {
                return this.renderSvnInfo(item);
              })}
            </div>
          )}

          <FormItem
            label={intl.get({
              id: 'code-assets.src.utils.locale.CodeLibraryName',
              defaultMessage: '代码库名称',
            })}
            required
          >
            {type === 'retry' ? (
              <AddonBeforeInputSpan text={projectName} />
            ) : (
              <Input
                spellCheck={false}
                placeholder={intl.get({
                  id: 'code-assets.src.utils.locale.EnterACodeLibraryName',
                  defaultMessage: '请输入代码库名称',
                })}
                {...init('name', {
                  rules: [
                    {
                      required: true,
                      message: intl.get({
                        id: 'code-assets.importProjectModal.svn.ThisParameterIsRequired',
                        defaultMessage: '该项为必填项',
                      }),
                    },

                    {
                      validator: this.nameValidator,
                    },
                  ],

                  initValue: projectName,
                })}
              />
            )}
          </FormItem>

          {type === 'retry' ? (
            <FormItem
              label={intl.get({
                id: 'code-assets.importProjectModal.svn.CodeLibraryPath',
                defaultMessage: '代码库路径',
              })}
              required
            >
              <AddonBeforeInputSpan text={web_url} />
            </FormItem>
          ) : (
            <div className="import-project-modal-path">
              <FormItem
                label={intl.get({
                  id: 'code-assets.importProjectModal.svn.CodeLibraryPath',
                  defaultMessage: '代码库路径',
                })}
                required
                className="origin"
              >
                <AddonBeforeInputSpan
                  text={`${window.location.origin}/${
                    organization.path || organization.organization_id
                  }`}
                />
              </FormItem>
              <FormItem label=" " className={`namespace_id ${namespaceIdFocus ? 'focus' : ''}`}>
                <GroupSelect
                  {...init('namespace_id', {
                    initValue: this.props.defaultNamespaceId || '',
                    rules: groupSelectRules,
                  })}
                  okFn={this.setGroupAccess}
                  style={{ width: '100%' }}
                  operateType={'create'}
                  type={'repo'}
                  setGroupNeedValidate={this.setGroupNeedValidate}
                  popupProps={{
                    align: 'bl tl',
                    needAdjust: false,
                    offset: [0, -4],
                  }}
                  isUsePath
                  popupStyle={{ width: 320 }}
                  autoWidth={false}
                  onFocus={() => {
                    this.setState({
                      namespaceIdFocus: true,
                    });
                  }}
                  onBlur={() => {
                    this.setState({
                      namespaceIdFocus: false,
                    });
                  }}
                />
              </FormItem>
              <FormItem label=" " className="path">
                <Input
                  spellCheck={false}
                  placeholder={intl.get({
                    id: 'code-assets.importProjectModal.svn.EnterAPath',
                    defaultMessage: '请输入路径',
                  })}
                  {...init('path', {
                    rules: [
                      {
                        required: true,
                        message: intl.get({
                          id: 'code-assets.src.utils.locale.ThisParameterIsRequired',
                          defaultMessage: '该项为必填项',
                        }),
                      },

                      {
                        validator: this.pathValidator,
                      },
                    ],
                  })}
                />
              </FormItem>
            </div>
          )}

          <FormItem
            label={intl.get({
              id: 'code-assets.src.utils.locale.Description.1',
              defaultMessage: '代码库描述',
            })}
          >
            <Input.TextArea
              placeholder={intl.get({
                id: 'code-assets.src.utils.locale.EnterADescription',
                defaultMessage: '请输入描述',
              })}
              {...init('description', {
                initValue: type === 'retry' ? description : '',
              })}
            />
          </FormItem>
          <FormItem
            required
            className="no-mr-b"
            label={
              <span>
                <span className="before-icon-text">
                  {intl.get({
                    id: 'code-assets.importProjectModal.svn.Openness',
                    defaultMessage: '公开性',
                  })}
                </span>
              </span>
            }
          >
            <AccessSelect
              placeholder={intl.get({
                id: 'code-assets.src.utils.locale.SelectPublicity',
                defaultMessage: '请选择公开性',
              })}
              {...init('visibility_level', {
                initValue:
                  type === 'retry' ? curProjectVisibilityLevel : ENUM.visibility_level.PRIVATE,
              })}
              groupAccess={this.state.groupAccess}
              onChange={this.handleChangeAccess}
              initValueFn={this.setVisibilityLevel}
              style={{ width: 270 }}
            />
          </FormItem>
        </Form>
      </React.Fragment>
    );
  }
}
